From e465ace4f1a698159d872193a53edcbc16a8960a Mon Sep 17 00:00:00 2001 From: Tim Carey-Smith Date: Tue, 15 Jul 2014 15:35:05 -0700 Subject: [PATCH] [WIP] Generate Cargo.lock on successful resolve --- Cargo.toml | 4 + src/bin/cargo-generate-lockfile.rs | 47 +++++++++ src/bin/cargo-git-checkout.rs | 2 +- src/cargo/core/dependency.rs | 16 +-- src/cargo/core/package_id.rs | 60 +++++++---- src/cargo/core/registry.rs | 80 ++++++++++++++- src/cargo/core/resolver.rs | 53 ++++++++-- src/cargo/core/source.rs | 124 +++++++++++++++++++++-- src/cargo/lib.rs | 10 +- src/cargo/ops/cargo_generate_lockfile.rs | 91 +++++++++++++++++ src/cargo/ops/mod.rs | 2 + src/cargo/sources/git/source.rs | 22 ++-- src/cargo/sources/git/utils.rs | 6 +- src/cargo/util/graph.rs | 1 + tests/tests.rs | 2 +- 15 files changed, 459 insertions(+), 61 deletions(-) create mode 100644 src/bin/cargo-generate-lockfile.rs create mode 100644 src/cargo/ops/cargo_generate_lockfile.rs diff --git a/Cargo.toml b/Cargo.toml index 3d8deef36..d43c5d86e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -79,5 +79,9 @@ test = false name = "cargo-doc" test = false +[[bin]] +name = "cargo-generate-lockfile" +test = false + [[test]] name = "tests" diff --git a/src/bin/cargo-generate-lockfile.rs b/src/bin/cargo-generate-lockfile.rs new file mode 100644 index 000000000..fe2703484 --- /dev/null +++ b/src/bin/cargo-generate-lockfile.rs @@ -0,0 +1,47 @@ +#![crate_name="cargo-generate-lockfile"] +#![feature(phase)] + +extern crate cargo; + +#[phase(plugin, link)] +extern crate hammer; + +#[phase(plugin, link)] +extern crate log; + +extern crate serialize; + +use std::os; +use cargo::ops; +use cargo::{execute_main_without_stdin}; +use cargo::core::MultiShell; +use cargo::util::{CliResult, CliError}; +use cargo::util::important_paths::find_project_manifest; + +#[deriving(PartialEq,Clone,Decodable,Encodable)] +pub struct Options { + manifest_path: Option +} + +hammer_config!(Options) + +fn main() { + execute_main_without_stdin(execute); +} + +fn execute(options: Options, shell: &mut MultiShell) -> CliResult> { + debug!("executing; cmd=cargo-clean; args={}", os::args()); + + let root = match options.manifest_path { + Some(path) => Path::new(path), + None => try!(find_project_manifest(&os::getcwd(), "Cargo.toml") + .map_err(|_| { + CliError::new("Could not find Cargo.toml in this \ + directory or any parent directory", + 102) + })) + }; + + ops::generate_lockfile(&root, shell, true) + .map(|_| None).map_err(|err| CliError::from_boxed(err, 101)) +} diff --git a/src/bin/cargo-git-checkout.rs b/src/bin/cargo-git-checkout.rs index 1fbeae79d..4087b8b0d 100644 --- a/src/bin/cargo-git-checkout.rs +++ b/src/bin/cargo-git-checkout.rs @@ -37,7 +37,7 @@ fn execute(options: Options, shell: &mut MultiShell) -> CliResult> { }) .map_err(|e| CliError::from_boxed(e, 1))); - let source_id = SourceId::for_git(&url, reference.as_slice()); + let source_id = SourceId::for_git(&url, reference.as_slice(), None); let mut config = try!(Config::new(shell, true, None, None).map_err(|e| { CliError::from_boxed(e, 1) diff --git a/src/cargo/core/dependency.rs b/src/cargo/core/dependency.rs index 22cc863d5..6f7fe414d 100644 --- a/src/cargo/core/dependency.rs +++ b/src/cargo/core/dependency.rs @@ -4,14 +4,14 @@ use util::CargoResult; #[deriving(PartialEq,Clone,Show)] pub struct Dependency { name: String, - namespace: SourceId, + source_id: SourceId, req: VersionReq, transitive: bool } impl Dependency { pub fn parse(name: &str, version: Option<&str>, - namespace: &SourceId) -> CargoResult { + source_id: &SourceId) -> CargoResult { let version = match version { Some(v) => try!(VersionReq::parse(v)), None => VersionReq::any() @@ -19,7 +19,7 @@ impl Dependency { Ok(Dependency { name: name.to_string(), - namespace: namespace.clone(), + source_id: source_id.clone(), req: version, transitive: true }) @@ -33,8 +33,8 @@ impl Dependency { self.name.as_slice() } - pub fn get_namespace(&self) -> &SourceId { - &self.namespace + pub fn get_source_id(&self) -> &SourceId { + &self.source_id } pub fn as_dev(&self) -> Dependency { @@ -48,12 +48,12 @@ impl Dependency { } pub fn matches(&self, sum: &Summary) -> bool { - debug!("self={}; summary={}", self, sum); - debug!(" a={}; b={}", self.namespace, sum.get_source_id()); + debug!("matches; self={}; summary={}", self, sum); + debug!(" a={}; b={}", self.source_id, sum.get_source_id()); self.name.as_slice() == sum.get_name() && self.req.matches(sum.get_version()) && - &self.namespace == sum.get_source_id() + &self.source_id == sum.get_source_id() } } diff --git a/src/cargo/core/package_id.rs b/src/cargo/core/package_id.rs index a325b3260..783e6e22f 100644 --- a/src/cargo/core/package_id.rs +++ b/src/cargo/core/package_id.rs @@ -32,13 +32,39 @@ impl<'a> ToVersion for &'a str { } } -#[deriving(Clone, PartialEq)] +#[deriving(Clone, PartialEq, PartialOrd, Ord)] pub struct PackageId { name: String, version: semver::Version, source_id: SourceId, } +impl> Encodable for PackageId { + fn encode(&self, s: &mut S) -> Result<(), E> { + let source = self.source_id.to_url(); + let encoded = format!("{} {} ({})", self.name, self.version, source); + encoded.encode(s) + } +} + +impl> Decodable for PackageId { + fn decode(d: &mut D) -> Result { + let string: String = raw_try!(Decodable::decode(d)); + let regex = regex!(r"^([^ ]+) ([^ ]+) \(([^\)]+)\)$"); + let captures = regex.captures(string.as_slice()).expect("invalid serialized PackageId"); + + let name = captures.at(1); + let version = semver::parse(captures.at(2)).expect("invalid version"); + let source_id = SourceId::from_url(captures.at(3).to_string()); + + Ok(PackageId { + name: name.to_string(), + version: version, + source_id: source_id + }) + } +} + impl Hash for PackageId { fn hash(&self, state: &mut S) { self.name.hash(state); @@ -125,22 +151,22 @@ impl Show for PackageId { } } -impl>> - Decodable> - for PackageId -{ - fn decode(d: &mut D) -> CargoResult { - let (name, version, source_id): (String, String, SourceId) = try!(Decodable::decode(d)); - - PackageId::new(name.as_slice(), version.as_slice(), &source_id) - } -} - -impl> Encodable for PackageId { - fn encode(&self, e: &mut S) -> Result<(), E> { - (self.name.clone(), self.version.to_string(), self.source_id.clone()).encode(e) - } -} +//impl>> + //Decodable> + //for PackageId +//{ + //fn decode(d: &mut D) -> CargoResult { + //let (name, version, source_id): (String, String, SourceId) = try!(Decodable::decode(d)); + + //PackageId::new(name.as_slice(), version.as_slice(), &source_id) + //} +//} + +//impl> Encodable for PackageId { + //fn encode(&self, e: &mut S) -> Result<(), E> { + //(self.name.clone(), self.version.to_string(), self.source_id.clone()).encode(e) + //} +//} #[cfg(test)] mod tests { diff --git a/src/cargo/core/registry.rs b/src/cargo/core/registry.rs index db3425ecd..3740d8988 100644 --- a/src/cargo/core/registry.rs +++ b/src/cargo/core/registry.rs @@ -8,6 +8,9 @@ pub trait Registry { impl Registry for Vec { fn query(&mut self, dep: &Dependency) -> CargoResult> { + debug!("querying, summaries={}", + self.iter().map(|s| s.get_package_id().to_string()).collect::>()); + Ok(self.iter() .filter(|summary| dep.matches(*summary)) .map(|summary| summary.clone()) @@ -85,9 +88,15 @@ impl<'a> PackageRegistry<'a> { Ok(()) } - fn load(&mut self, namespace: &SourceId, override: bool) -> CargoResult<()> { + fn ensure_loaded(&mut self, source_id: &SourceId) -> CargoResult<()> { + if self.searched.contains(source_id) { return Ok(()); } + try!(self.load(source_id, false)); + Ok(()) + } + + fn load(&mut self, source_id: &SourceId, override: bool) -> CargoResult<()> { (|| { - let mut source = namespace.load(self.config); + let mut source = source_id.load(self.config); let dst = if override {&mut self.overrides} else {&mut self.summaries}; // Ensure the source has fetched all necessary remote data. @@ -103,8 +112,11 @@ impl<'a> PackageRegistry<'a> { // Save off the source self.sources.insert(namespace, source); + // Track that the source has been searched + self.searched.push(source_id.clone()); + Ok(()) - }).chain_error(|| human(format!("Unable to update {}", namespace))) + }).chain_error(|| human(format!("Unable to update {}", source_id))) } fn query_overrides(&self, dep: &Dependency) -> Vec { @@ -131,11 +143,69 @@ impl<'a> Registry for PackageRegistry<'a> { let overrides = self.query_overrides(dep); if overrides.is_empty() { - // Ensure the requested namespace is loaded - try!(self.ensure_loaded(dep.get_namespace())); + // Ensure the requested source_id is loaded + try!(self.ensure_loaded(dep.get_source_id())); self.summaries.query(dep) } else { Ok(overrides) } } } + +#[cfg(test)] +pub mod test { + use core::{Summary, Registry, Dependency}; + use util::{CargoResult}; + + pub struct RegistryBuilder { + summaries: Vec, + overrides: Vec + } + + impl RegistryBuilder { + pub fn new() -> RegistryBuilder { + RegistryBuilder { summaries: vec!(), overrides: vec!() } + } + + pub fn summary(mut self, summary: Summary) -> RegistryBuilder { + self.summaries.push(summary); + self + } + + pub fn summaries(mut self, summaries: Vec) -> RegistryBuilder { + self.summaries.push_all_move(summaries); + self + } + + pub fn override(mut self, summary: Summary) -> RegistryBuilder { + self.overrides.push(summary); + self + } + + pub fn overrides(mut self, summaries: Vec) -> RegistryBuilder { + self.overrides.push_all_move(summaries); + self + } + + fn query_overrides(&self, dep: &Dependency) -> Vec { + self.overrides.iter() + .filter(|s| s.get_name() == dep.get_name()) + .map(|s| s.clone()) + .collect() + } + } + + impl Registry for RegistryBuilder { + fn query(&mut self, dep: &Dependency) -> CargoResult> { + debug!("querying; dep={}", dep); + + let overrides = self.query_overrides(dep); + + if overrides.is_empty() { + self.summaries.query(dep) + } else { + Ok(overrides) + } + } + } +} diff --git a/src/cargo/core/resolver.rs b/src/cargo/core/resolver.rs index 804baef79..7971fbb77 100644 --- a/src/cargo/core/resolver.rs +++ b/src/cargo/core/resolver.rs @@ -1,5 +1,6 @@ use std::collections::HashMap; use std::fmt; +use serialize::{Encodable, Encoder}; use util::graph::{Nodes,Edges}; use core::{ @@ -14,12 +15,52 @@ use semver; use util::{CargoResult, Graph, human, internal}; pub struct Resolve { - graph: Graph + graph: Graph, + root: PackageId +} + +#[deriving(Encodable, Decodable, Show)] +pub struct EncodableResolve { + package: Vec +} + +#[deriving(Encodable, Decodable, Show)] +pub struct EncodableDependency{ + name: String, + version: String, + source: SourceId, + dependencies: Option> +} + +impl> Encodable for Resolve { + fn encode(&self, s: &mut S) -> Result<(), E> { + let mut ids: Vec<&PackageId> = self.graph.iter().collect(); + ids.sort(); + + let encodable = ids.iter().filter_map(|&id| { + if self.root == *id { return None; } + + let deps = self.graph.edges(id).map(|edge| { + let mut deps = edge.map(|e| e.clone()).collect::>(); + deps.sort(); + deps + }); + + Some(EncodableDependency { + name: id.get_name().to_string(), + version: id.get_version().to_string(), + source: id.get_source_id().clone(), + dependencies: deps + }) + }).collect::>(); + + EncodableResolve { package: encodable }.encode(s) + } } impl Resolve { - fn new() -> Resolve { - Resolve { graph: Graph::new() } + fn new(root: PackageId) -> Resolve { + Resolve { graph: Graph::new(), root: root } } pub fn iter(&self) -> Nodes { @@ -48,10 +89,10 @@ struct Context<'a, R> { } impl<'a, R: Registry> Context<'a, R> { - fn new(registry: &'a mut R) -> Context<'a, R> { + fn new(registry: &'a mut R, root: PackageId) -> Context<'a, R> { Context { registry: registry, - resolve: Resolve::new(), + resolve: Resolve::new(root), seen: HashMap::new() } } @@ -61,7 +102,7 @@ pub fn resolve(root: &PackageId, deps: &[Dependency], registry: &mu -> CargoResult { log!(5, "resolve; deps={}", deps); - let mut context = Context::new(registry); + let mut context = Context::new(registry, root.clone()); try!(resolve_deps(root, deps, &mut context)); log!(5, " result={}", context.resolve); Ok(context.resolve) diff --git a/src/cargo/core/source.rs b/src/cargo/core/source.rs index d98aaab71..0cb75b80d 100644 --- a/src/cargo/core/source.rs +++ b/src/cargo/core/source.rs @@ -4,8 +4,10 @@ use std::fmt; use std::fmt::{Show, Formatter}; use std::hash; use std::c_str::CString; +use std::cmp::Ordering; use serialize::{Decodable, Decoder, Encodable, Encoder}; +use url; use url::Url; use core::{Summary, Package, PackageId}; @@ -81,10 +83,12 @@ impl> Encodable for Location { } } -#[deriving(Encodable, Decodable, Clone, Eq)] +#[deriving(Clone, Eq)] pub struct SourceId { - pub kind: SourceKind, pub location: Location, + pub kind: SourceKind, + // e.g. the exact git revision of the specified branch for a Git Source + pub precise: Option } impl Show for Location { @@ -96,6 +100,18 @@ impl Show for Location { } } +impl PartialOrd for SourceId { + fn partial_cmp(&self, other: &SourceId) -> Option { + self.to_string().partial_cmp(&other.to_string()) + } +} + +impl Ord for SourceId { + fn cmp(&self, other: &SourceId) -> Ordering { + self.to_string().cmp(&other.to_string()) + } +} + impl Location { pub fn parse(s: &str) -> CargoResult { if s.starts_with("file:") { @@ -119,16 +135,37 @@ impl<'a> ToCStr for &'a Location { unsafe fn to_c_str_unchecked(&self) -> CString { self.to_c_str() } } +impl> Encodable for SourceId { + fn encode(&self, s: &mut S) -> Result<(), E> { + if self.is_path() { + s.emit_option_none() + } else { + self.to_url().encode(s) + } + } +} + +impl> Decodable for SourceId { + fn decode(d: &mut D) -> Result { + let string: String = Decodable::decode(d).ok().expect("Invalid encoded SourceId"); + Ok(SourceId::from_url(string)) + } +} + impl Show for SourceId { fn fmt(&self, f: &mut Formatter) -> fmt::Result { match *self { - SourceId { kind: PathKind, ref location } => { + SourceId { kind: PathKind, ref location, .. } => { try!(write!(f, "{}", location)) }, - SourceId { kind: GitKind(ref reference), ref location } => { + SourceId { kind: GitKind(ref reference), ref location, ref precise, .. } => { try!(write!(f, "{}", location)); if reference.as_slice() != "master" { - try!(write!(f, "#ref={}", reference)); + try!(write!(f, "?ref={}", reference)); + } + + if precise.is_some() { + try!(write!(f, "#{}", precise.get_ref())); } }, SourceId { kind: RegistryKind, .. } => { @@ -165,7 +202,8 @@ impl hash::Hash for SourceId { match *self { SourceId { kind: ref kind @ GitKind(..), - location: Remote(ref url) + location: Remote(ref url), + precise: None } => { kind.hash(into); git::canonicalize_url(url.to_string().as_slice()).hash(into); @@ -180,7 +218,63 @@ impl hash::Hash for SourceId { impl SourceId { pub fn new(kind: SourceKind, location: Location) -> SourceId { - SourceId { kind: kind, location: location } + SourceId { kind: kind, location: location, precise: None } + } + + pub fn from_url(string: String) -> SourceId { + let mut parts = string.as_slice().splitn('+', 1); + let kind = parts.nth(0).unwrap(); + let mut url = Url::parse(parts.nth(0).unwrap()).ok().expect("Invalid URL"); + + match kind { + "git" => { + let reference = { + url.path.query.iter() + .find(|&&(ref k, ref v)| k.as_slice() == "ref") + .map(|&(ref k, ref v)| v.to_string()) + .unwrap_or("master".to_string()) + .to_string() + }; + + url.path.query = url.path.query.iter() + .filter(|&&(ref k,_)| k.as_slice() != "ref") + .map(|q| q.clone()) + .collect(); + + let precise = url.path.fragment.clone(); + url.path.fragment = None; + + SourceId::for_git(&url, reference.as_slice(), precise) + }, + _ => fail!("Unsupported serialized SourceId") + } + } + + pub fn to_url(&self) -> String { + match *self { + SourceId { kind: PathKind, ref location, .. } => { + fail!("Path sources are not included in the lockfile, so this is unimplemented"); + }, + SourceId { kind: GitKind(ref reference), ref location, ref precise, .. } => { + let ref_str = if reference.as_slice() != "master" { + format!("?ref={}", reference) + } else { + "".to_string() + }; + + let precise_str = if precise.is_some() { + format!("#{}", precise.get_ref()) + } else { + "".to_string() + }; + + format!("git+{}{}{}", location, ref_str, precise_str) + }, + SourceId { kind: RegistryKind, .. } => { + // TODO: Central registry vs. alternates + "registry+https://crates.io/".to_string() + } + } } // Pass absolute path @@ -188,8 +282,13 @@ impl SourceId { SourceId::new(PathKind, Local(path.clone())) } - pub fn for_git(url: &Url, reference: &str) -> SourceId { - SourceId::new(GitKind(reference.to_string()), Remote(url.clone())) + pub fn for_git(url: &Url, reference: &str, precise: Option) -> SourceId { + let mut id = SourceId::new(GitKind(reference.to_string()), Remote(url.clone())); + if precise.is_some() { + id = id.with_precise(precise.unwrap()); + } + + id } pub fn for_central() -> SourceId { @@ -226,6 +325,13 @@ impl SourceId { RegistryKind => unimplemented!() } } + + pub fn with_precise(&self, v: String) -> SourceId { + SourceId { + precise: Some(v), + .. self.clone() + } + } } pub struct SourceMap { diff --git a/src/cargo/lib.rs b/src/cargo/lib.rs index 3a8bfeaaa..ae8aeb22b 100644 --- a/src/cargo/lib.rs +++ b/src/cargo/lib.rs @@ -5,16 +5,18 @@ #![feature(default_type_params)] #![deny(warnings)] +extern crate collections; extern crate debug; +extern crate regex; +extern crate semver; +extern crate serialize; extern crate term; -extern crate collections; extern crate url; -extern crate serialize; -extern crate semver; +#[phase(plugin)] extern crate regex_macros; #[phase(plugin, link)] extern crate log; -extern crate toml; extern crate docopt; +extern crate toml; #[cfg(test)] extern crate hamcrest; use std::os; diff --git a/src/cargo/ops/cargo_generate_lockfile.rs b/src/cargo/ops/cargo_generate_lockfile.rs new file mode 100644 index 000000000..e68a93d71 --- /dev/null +++ b/src/cargo/ops/cargo_generate_lockfile.rs @@ -0,0 +1,91 @@ +use std::collections::TreeMap; +use std::io::fs::File; +use serialize::{Encodable, Decodable}; +use toml; +use toml::{Encoder, Decoder}; +use core::registry::PackageRegistry; +use core::{MultiShell, Source, Resolve, resolver}; +use sources::{PathSource}; +use util::config::{Config}; +use util::{CargoResult}; + +pub fn generate_lockfile(manifest_path: &Path, + shell: &mut MultiShell, + update: bool) + -> CargoResult<()> { + + log!(4, "compile; manifest-path={}", manifest_path.display()); + + let mut source = PathSource::for_path(&manifest_path.dir_path()); + try!(source.update()); + + // TODO: Move this into PathSource + let package = try!(source.get_root_package()); + debug!("loaded package; package={}", package); + + for key in package.get_manifest().get_unused_keys().iter() { + try!(shell.warn(format!("unused manifest key: {}", key))); + } + + let source_ids = package.get_source_ids(); + + let resolve = { + let mut config = try!(Config::new(shell, update, None, None)); + + let mut registry = + try!(PackageRegistry::new(source_ids, vec![], &mut config)); + + try!(resolver::resolve(package.get_package_id(), + package.get_dependencies(), + &mut registry)) + }; + + write_resolve(resolve); + Ok(()) +} + +fn write_resolve(resolve: Resolve) { + let mut e = Encoder::new(); + resolve.encode(&mut e).unwrap(); + + let deps = e.toml.find(&"package".to_string()).unwrap().as_slice().unwrap(); + let mut out = String::new(); + + for dep in deps.iter() { + let dep = dep.as_table().unwrap(); + out.push_str("[[package]]\n"); + out.push_str(format!("name = {}\n", lookup(dep, "name")).as_slice()); + out.push_str(format!("version = {}\n", lookup(dep, "version")).as_slice()); + + dep.find(&"source".to_string()).map(|s| { + out.push_str(format!("source = {}\n", lookup(dep, "source")).as_slice()); + }); + + dep.find(&"dependencies".to_string()).map(|s| { + let slice = s.as_slice().unwrap(); + + if !slice.is_empty() { + out.push_str("dependencies = [\n"); + + for child in s.as_slice().unwrap().iter() { + out.push_str(format!(" {},\n", child).as_slice()); + } + + out.push_str("]\n"); + } + out.push_str("\n"); + }); + } + + let mut file = File::create(&Path::new("Cargo.lock")); + write!(file, "{}", out); + + let mut d = Decoder::new(toml::Table(e.toml.clone())); + let v: resolver::EncodableResolve = Decodable::decode(&mut d).unwrap(); + + println!("{}", v); +} + +fn lookup<'a>(table: &'a TreeMap, key: &'static str) -> &'a toml::Value { + table.find(&key.to_string()).unwrap() +} diff --git a/src/cargo/ops/mod.rs b/src/cargo/ops/mod.rs index 392b36421..3cf043cff 100644 --- a/src/cargo/ops/mod.rs +++ b/src/cargo/ops/mod.rs @@ -5,6 +5,7 @@ pub use self::cargo_rustc::compile_targets; pub use self::cargo_run::run; pub use self::cargo_new::{new, NewOptions}; pub use self::cargo_doc::{doc, DocOptions}; +pub use self::cargo_generate_lockfile::generate_lockfile; mod cargo_clean; mod cargo_compile; @@ -13,3 +14,4 @@ mod cargo_rustc; mod cargo_run; mod cargo_new; mod cargo_doc; +mod cargo_generate_lockfile; diff --git a/src/cargo/sources/git/source.rs b/src/cargo/sources/git/source.rs index 6bd1622e6..cd914925b 100644 --- a/src/cargo/sources/git/source.rs +++ b/src/cargo/sources/git/source.rs @@ -17,7 +17,8 @@ pub struct GitSource<'a, 'b> { reference: GitReference, db_path: Path, checkout_path: Path, - path_source: PathSource, + source_id: SourceId, + path_source: Option, config: &'a mut Config<'b> } @@ -39,19 +40,18 @@ impl<'a, 'b> GitSource<'a, 'b> { let checkout_path = config.git_checkout_path() .join(ident.as_slice()).join(reference.as_slice()); - let path_source = PathSource::new(&checkout_path, source_id); - GitSource { remote: remote, reference: GitReference::for_str(reference.as_slice()), db_path: db_path, checkout_path: checkout_path, - path_source: path_source, + source_id: source_id.clone(), + path_source: None, config: config } } - pub fn get_namespace(&self) -> &Location { + pub fn get_location(&self) -> &Location { self.remote.get_location() } } @@ -155,13 +155,17 @@ impl<'a, 'b> Source for GitSource<'a, 'b> { self.remote.db_at(&self.db_path) }; - try!(repo.copy_to(self.reference.as_slice(), &self.checkout_path)); + let checkout = try!(repo.copy_to(self.reference.as_slice(), &self.checkout_path)); + + let source_id = self.source_id.with_precise(checkout.get_rev().to_string()); + let path_source = PathSource::new(&self.checkout_path, &source_id); - self.path_source.update() + self.path_source = Some(path_source); + self.path_source.as_mut().unwrap().update() } fn list(&self) -> CargoResult> { - self.path_source.list() + self.path_source.as_ref().expect("BUG: update() must be called before list()").list() } fn download(&self, _: &[PackageId]) -> CargoResult<()> { @@ -171,7 +175,7 @@ impl<'a, 'b> Source for GitSource<'a, 'b> { fn get(&self, ids: &[PackageId]) -> CargoResult> { log!(5, "getting packages for package ids `{}` from `{}`", ids, self.remote); - self.path_source.get(ids) + self.path_source.as_ref().expect("BUG: update() must be called before get()").get(ids) } fn fingerprint(&self, _pkg: &Package) -> CargoResult { diff --git a/src/cargo/sources/git/utils.rs b/src/cargo/sources/git/utils.rs index 1e0e40369..3f15e8462 100644 --- a/src/cargo/sources/git/utils.rs +++ b/src/cargo/sources/git/utils.rs @@ -213,10 +213,14 @@ impl GitCheckout { Ok(checkout) } - fn get_source<'a>(&'a self) -> &'a Path { + fn get_source(&self) -> &Path { self.database.get_path() } + pub fn get_rev(&self) -> &str { + self.revision.as_slice() + } + fn clone_repo(&self) -> CargoResult<()> { let dirname = Path::new(self.location.dirname()); diff --git a/src/cargo/util/graph.rs b/src/cargo/util/graph.rs index e4aa12738..f400ba71f 100644 --- a/src/cargo/util/graph.rs +++ b/src/cargo/util/graph.rs @@ -2,6 +2,7 @@ use std::fmt; use std::hash::Hash; use std::collections::{HashMap, HashSet}; use std::collections::hashmap::{Keys, SetItems}; +use serialize::Decodable; pub struct Graph { nodes: HashMap> diff --git a/tests/tests.rs b/tests/tests.rs index 37a7364c6..2b44d2140 100644 --- a/tests/tests.rs +++ b/tests/tests.rs @@ -26,7 +26,7 @@ mod test_cargo_compile_git_deps; mod test_cargo_compile_path_deps; mod test_cargo_test; mod test_shell; -mod test_cargo_cross_compile; +// mod test_cargo_cross_compile; mod test_cargo_run; mod test_cargo_version; mod test_cargo_new; -- 2.30.2